"""
任务队列 - 专用装饰器
"""
from functools import wraps
import inspect
from typing import Callable


def task(**arq_task_options):
    """
    一个高级的任务装饰器，将一个函数标记为 ARQ 任务。

    此装饰器会创建一个异步包装器，该包装器自动处理依赖注入。
    它会检查原始任务函数的类型注解，从 ARQ Worker 的上下文中获取 DI 容器，
    并注入所需的 Service 实例。
    """
    def decorator(func: Callable):
        # 提取原始函数的参数签名，以找出需要注入的依赖
        original_sig = inspect.signature(func)
        
        @wraps(func)
        async def wrapper(ctx, *args, **kwargs):
            # 从 ARQ 上下文中获取 DI 容器
            app_context = ctx.get('axiom_app_context')
            if not app_context:
                raise RuntimeError("无法从 ARQ 上下文中获取 axiom_app_context。")

            injected_kwargs = {}
            # 遍历函数签名中的参数
            for param in original_sig.parameters.values():
                # 如果参数有类型注解，并且不是 ARQ 的 ctx，就尝试从 DI 容器获取
                if param.annotation != inspect.Parameter.empty and param.name != 'ctx':
                    # [关键修复] 在注入前，先检查该类型是否是一个已定义的服务
                    if app_context.has_definition_for(param.annotation):
                        try:
                            # [关键修复] 在异步包装器中，应直接使用异步的 get 方法
                            injected_kwargs[param.name] = await app_context.get(param.annotation)
                        except Exception as e:
                            raise RuntimeError(f"为任务 '{func.__name__}' 注入依赖 '{param.name}: {param.annotation.__name__}' 时失败: {e}")

            # [关键修复] 合并注入的依赖和用户传入的关键字参数，并以正确的顺序调用
            final_kwargs = {**injected_kwargs, **kwargs}
            return await func(*args, **final_kwargs)

        # 附加元数据，供任务发现器识别
        setattr(wrapper, '_is_axiom_task', True)
        # [关键修复] 将属性名修改为 arq 框架能自动识别的 'arq_task_settings'
        setattr(wrapper, 'arq_task_settings', arq_task_options)
        
        # 将原始函数的名称赋给包装器，ARQ 会使用它作为任务名
        wrapper.__name__ = func.__name__

        return wrapper
    return decorator
